package com.neusoft.databus.agent.interactive.collect;

import java.lang.reflect.Constructor;
import java.util.Map;

import com.neusoft.bizcore.web.utils.JsonUtils;
import com.neusoft.databus.agent.parser.ParserFactory;
import com.neusoft.databus.common.bean.CommandBean;
import com.neusoft.databus.common.constant.DatabusConstant;
import com.neusoft.databus.common.enums.PhysicalConnType;
import com.neusoft.databus.common.enums.Protocol;
import com.neusoft.databus.common.exception.ConfigErrorException;
import com.neusoft.databus.common.interactive.collect.Collector;
import com.neusoft.databus.common.parser.Parser;

/**
 * The collector provider based on protocol.
 *
 * @author sunchf
 * @date 2019年1月8日 上午10:44:11
 */
public interface CollectorProvider {

    default Collector<?> getCollector(final CommandBean commandBean) {

        final Parser parser = ParserFactory.createParser(commandBean);
        final Protocol protocol = commandBean.getProtocol();
        Collector<?> collector = null;
        switch (protocol) {
        case MODBUS_RTU:
        case MODBUS_TCP:
        case MODBUS_ASCII:
            if (PhysicalConnType.SOCKET.equals(commandBean.getConnType())) {
                collector = new SocketModbusCollector(parser);
            } else if (PhysicalConnType.SOCKET2.equals(commandBean.getConnType())) {
                collector = new Socket2ModbusCollector(parser);
            } else if (PhysicalConnType.SERIAL.equals(commandBean.getConnType())) {
                collector = new SerialModbusCollector(parser);
            } else if (PhysicalConnType.NETTY.equals(commandBean.getConnType())) {
                collector = new NettyModbusCollector(parser);
            }
            break;
        case OPC:
            collector = new OpcOpcCollector(parser);
            break;
        case SNMP:
            collector = new SnmpSnmpCollector(parser);
            break;
        case PLUGIN:
            final String connectionConfig = commandBean.getConnectionStr();
            final String protocolConfig = commandBean.getProtocolConfig();
            Map<String, Object> connectionMap = null;
            try {
                connectionMap = JsonUtils.jsonToMap(connectionConfig);
            } catch (final Exception e) {
                throw new ConfigErrorException("网关配置解析错误, %s", commandBean.getConnectionStr());
            }
            if ((null == connectionMap) || !connectionMap.containsKey("connName")) {
                throw new ConfigErrorException("网关配置未指定connName");
            }

            Map<String, Object> protocolMap = null;
            try {
                protocolMap = JsonUtils.jsonToMap(protocolConfig);
            } catch (final Exception e) {
                throw new ConfigErrorException("协议配置解析错误, %s", protocolConfig);
            }
            if ((null == protocolMap) || !protocolMap.containsKey("protocolName")) {
                throw new ConfigErrorException("协议配置未指定protocolName");
            }

            final String connName = (String) connectionMap.get("connName");
            final String protocolName = (String) protocolMap.get("protocolName");
            final StringBuilder sb = new StringBuilder();
            sb.append(DatabusConstant.PACKAGE_PREFIX_COLLECTOR_CLASS)
                    .append(connName.substring(0, 1).toUpperCase())
                    .append(connName.substring(1, connName.length()).toLowerCase())
                    .append(protocolName.substring(0, 1).toUpperCase())
                    .append(protocolName.substring(1, protocolName.length()).toLowerCase()).append("Collector");
            try {
                @SuppressWarnings({"rawtypes", "unchecked" })
                final Class<Collector> clazz = (Class<Collector>) Class.forName(sb.toString());
                @SuppressWarnings("rawtypes")
                final Constructor<Collector> ct = clazz.getDeclaredConstructor(new Class[] {Parser.class });
                ct.setAccessible(true);
                collector = ct.newInstance(new Object[] {parser });
            } catch (final ClassNotFoundException e) {
                throw new ConfigErrorException("使用自定义的数据采集，但系统未找到指定的类%s", sb.toString());
            } catch (final Exception e) {
                throw new ConfigErrorException("使用自定义的数据采集，实例化插件出错", e);
            }
            break;
        default:
            throw new ConfigErrorException("不支持的数据采集协议");
        }

        return collector;
    }
}
